package oa.hleast.xswl.service.blog.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import oa.hleast.common.utils.ImagerListUtil;
import oa.hleast.common.web.exception.BizException;
import oa.hleast.common.web.util.RequestUtils;
import oa.hleast.xswl.common.constant.ReviewStatusEnum;
import oa.hleast.xswl.common.enums.SignSourceTypeEnum;
import oa.hleast.xswl.mapper.blog.UmsBlogCommentMapper;
import oa.hleast.xswl.mapper.blog.UmsBlogInfoMapper;
import oa.hleast.xswl.mapper.blog.UmsBlogLikeMapper;
import oa.hleast.xswl.pojo.domain.blog.*;
import oa.hleast.xswl.pojo.dto.UmsUserDto;
import oa.hleast.xswl.pojo.form.blog.BlogDisplayForm;
import oa.hleast.xswl.pojo.form.blog.ReviewForm;
import oa.hleast.xswl.pojo.form.blog.UmsBlogCommentForm;
import oa.hleast.xswl.pojo.form.blog.UmsBlogInfoForm;
import oa.hleast.xswl.pojo.form.clockin.UmsClockInForm;
import oa.hleast.xswl.pojo.vo.blog.UmsBlogCommentVo;
import oa.hleast.xswl.pojo.vo.blog.UmsBlogInfoVo;
import oa.hleast.xswl.pojo.vo.blog.UmsBlogTableVo;
import oa.hleast.xswl.service.IUmsUserService;
import oa.hleast.xswl.service.blog.*;
import oa.hleast.xswl.service.clockin.IClockInService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author 302
 * @date 2021/4/8
 */

@Transactional
@Slf4j
@Service
@AllArgsConstructor
public class BlogInfoServiceImpl extends ServiceImpl<UmsBlogInfoMapper, UmsBlogInfo> implements IBlogInfoService {

    private final UmsBlogCommentMapper blogCommentMapper;
    private final UmsBlogLikeMapper blogLikeMapper;
    private final IUmsUserService userService;
    private final IBlogLikeService likeService;
    private final IBlogCommentService commentService;
    private final IBlogTableService tableService;
    private final IBlogInfoTableService blogInfoTableService;
    private final IClockInService clockInService;

    @Override
    public boolean likeBlog(Long blogId, Long userId) {
        UmsUserDto userDto = userService.getUserDtoById(userId);
        if (ObjectUtils.isEmpty(userDto)) {
            throw new BizException("用户不存在");
        }

        UmsBlogInfo blogInfoOld = this.getById(blogId);
        if (ObjectUtils.isEmpty(blogInfoOld)) {
            throw new BizException("文章不存在");
        }

        //判断此数据是否已点赞
        QueryWrapper<UmsBlogLike> condition = new QueryWrapper<UmsBlogLike>()
                .eq("blog_id", blogId)
                .eq("like_user_id", userId)
                .last("limit 1");
        Integer count = blogLikeMapper.selectCount(condition);

        if (count > 0) {
            // 已点赞 -> 取消点赞
            // 1, 删除点赞记录
            boolean update = likeService.update(new LambdaUpdateWrapper<UmsBlogLike>()
                    .set(UmsBlogLike::getDeleted, true)
                    .eq(UmsBlogLike::getLikeUserId, userId)
                    .eq(UmsBlogLike::getBlogId, blogId));

            // 2， 减少点赞数
            boolean blogUpdate = this.update(new LambdaUpdateWrapper<UmsBlogInfo>().setSql("like_num = like_num - 1").eq(UmsBlogInfo::getId, blogId));
            return update & blogUpdate;
        } else {
            // 未点赞 -> 点赞
            // 1, 保存点赞记录
            UmsBlogLike blogLike = UmsBlogLike.builder()
                    .blogId(blogInfoOld.getId())
                    .likeUserId(userDto.getId())
                    .build();
            boolean likeSave = likeService.save(blogLike);

            // 2， 增加点赞数
            boolean blogUpdate = this.update(new LambdaUpdateWrapper<UmsBlogInfo>().setSql("like_num = like_num + 1").eq(UmsBlogInfo::getId, blogId));
            return likeSave & blogUpdate;
        }
    }

    /**
     * 判断是否评论
     */
    @Override
    public boolean isComment(Long blogId, Long userId) {

        //判断此数据是否已评论
        QueryWrapper<UmsBlogComment> condition = new QueryWrapper<UmsBlogComment>()
                .eq("blog_id", blogId)
                .eq("comment_user_id", userId)
                .last("limit 1");
        Integer count = blogCommentMapper.selectCount(condition);

        log.info("blogId = {},userId = {},count = {}", blogId, userId, count);
        if (count > 0) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 判断是否点赞
     */
    @Override
    public boolean isLike(Long blogId, Long userId) {

        //判断此数据是否已点赞
        QueryWrapper<UmsBlogLike> queryWrapper = new QueryWrapper<UmsBlogLike>()
                .eq("blog_id", blogId)
                .eq("like_user_id", userId)
                .last("limit 1");
        Integer count = blogLikeMapper.selectCount(queryWrapper);

        log.info("blogId = {},userId = {},count = {}", blogId, userId, count);
        if (count > 0) {
            return true;
        } else {
            return false;
        }
    }

    @Override
    public boolean commentBlog(UmsBlogCommentForm form, Long userId) {
        UmsUserDto userDto = userService.getUserDtoById(userId);
        if (ObjectUtils.isEmpty(userDto)) {
            throw new BizException("用户不存在");
        }

        UmsBlogInfo blogInfoOld = this.getById(form.getBlogId());
        if (ObjectUtils.isEmpty(blogInfoOld)) {
            throw new BizException("文章不存在");
        }

        // 1， 保存文章评论
        UmsBlogComment blogComment = conversionToCommentPojo(form);
        //现在不需要多层级的评论回复，评论层级先为 1
        blogComment.setLeve(1);
        blogComment.setCommentUserId(userDto.getId());
        blogComment.setCommentUserName(userDto.getNickname());
        blogComment.setCommentUserAvatar(userDto.getAvatar());
        boolean commentSave = commentService.save(blogComment);

        // 2， 更新评论数
        blogInfoOld.setCommentNum(blogInfoOld.getCommentNum() + 1);
        boolean update = this.updateById(blogInfoOld);

        return commentSave & update;
    }

    @Override
    public List<UmsBlogCommentVo> findCommentList(Long blogId, Long userId) {
        LambdaQueryWrapper<UmsBlogComment> queryWrapper = new LambdaQueryWrapper<UmsBlogComment>()
                .eq(UmsBlogComment::getBlogId, blogId)
                .orderByDesc(UmsBlogComment::getGmtModified)
                .orderByDesc(UmsBlogComment::getGmtCreate);

        List<UmsBlogComment> list = commentService.list(queryWrapper);

        boolean isNotEmptyUser = ObjectUtils.isNotEmpty(userId);
        long sysTime = System.currentTimeMillis();
        List<UmsBlogCommentVo> voList = list.stream().map(
                vo -> {
                    UmsBlogCommentVo umsBlogCommentVo = conversionToCommentVo(vo);
                    if (isNotEmptyUser) {
                        umsBlogCommentVo.setComment(this.isComment(vo.getBlogId(), vo.getCommentUserId()));
                    }
                    umsBlogCommentVo.setSysTime(sysTime);
                    return umsBlogCommentVo;
                }
        ).collect(Collectors.toList());
        log.info("voList = {}", voList);
        return voList;
    }

    @Override
    public boolean updateComment(Long userId, UmsBlogInfoForm form) {
        UmsBlogInfo umsBlogInfoOld = this.getById(form.getId());
        if (!userId.equals(umsBlogInfoOld.getUserId())) {
            throw new BizException("您只能修改自己的文章");
        }

        BeanUtil.copyProperties(form, umsBlogInfoOld);

        boolean update = this.updateById(umsBlogInfoOld);

        return update;
    }

    @Override
    public boolean del(Long userId, Long blogId) {
        UmsBlogInfo umsBlogInfoOld = this.getById(blogId);

        if (ObjectUtils.isEmpty(umsBlogInfoOld)) {
            throw new BizException("文章不存在");
        }
        if (!userId.equals(umsBlogInfoOld.getUserId())) {
            throw new BizException("您只能删除自己的文章");
        }

        umsBlogInfoOld.setDisplay(false);
        umsBlogInfoOld.setDelUser(userId + "");
        boolean updateStatus = this.updateById(umsBlogInfoOld);

        return updateStatus;
    }

    @Override
    public boolean reviewBlog(ReviewForm form) {
        UmsBlogInfo blogInfoOld = this.getById(form.getBlogId());
        if (ObjectUtils.isEmpty(blogInfoOld)) {
            throw new BizException("文章不存在");
        }


        ReviewStatusEnum anEnum = ReviewStatusEnum.getEnum(form.getReviewStatus());
        log.info("anEnum = {}, status = {}", anEnum, form.getReviewStatus());
        if (ObjectUtils.isEmpty(anEnum)) {
            throw new BizException("审核状态错误");
        }
        blogInfoOld.setReason(form.getReason());
        blogInfoOld.setReviewStatus(anEnum.getCode());
        if (ReviewStatusEnum.PASS.name().equals(anEnum.name())) {
            blogInfoOld.setDisplay(true);
        }

        boolean update = this.updateById(blogInfoOld);

        return update;
    }

    @Override
    public UmsBlogTableVo saveTable(Long userId, String name) {
        //TODO 校验name

        UmsBlogTable blogTable = UmsBlogTable.builder().userId(userId).name(name).build();
        boolean save = tableService.save(blogTable);
        if (!save) {
            throw new BizException("保存标签失败");
        }

        return conversionToTableVo(tableService.getById(blogTable.getId()));
    }

    @Override
    public boolean updateHot(Long id, Boolean hot) {
        UmsBlogInfo umsBlogInfoOld = this.getById(id);
        if (ObjectUtils.isEmpty(umsBlogInfoOld)) {
            throw new BizException("此数据不存在");
        }
        if (ObjectUtils.isEmpty(hot)) {
            throw new BizException("状态错误");
        }

        Boolean oldHot = umsBlogInfoOld.getHot();

        //热门 -> 热门
        if (oldHot && hot) {
            return true;
        }

        //非热门 -> 非热门
        if (!oldHot && !hot) {
            return true;
        }

        //非热门 -> 热门
        if (!oldHot) {
            //这里直接加1应该也没关系，热度值并发要求没有那么高
            UmsBlogInfo umsBlogInfo = this.getOne(new LambdaQueryWrapper<UmsBlogInfo>().orderByDesc(UmsBlogInfo::getSort).last("limit 1"));
            return this.update(new LambdaUpdateWrapper<UmsBlogInfo>()
                    .set(UmsBlogInfo::getSort, umsBlogInfo.getSort() + 1)
                    .set(UmsBlogInfo::getHot, true)
                    .eq(UmsBlogInfo::getId, id));
        }

        //热门 -> 非热门
        return this.update(new LambdaUpdateWrapper<UmsBlogInfo>()
                .set(UmsBlogInfo::getSort, 0)
                .set(UmsBlogInfo::getHot, false)
                .eq(UmsBlogInfo::getId, id));
    }

    @Override
    public boolean updateDisplay(Long id, Boolean display, String downReason) {
        UmsBlogInfo umsBlogInfoOld = this.getById(id);
        if (ObjectUtils.isEmpty(umsBlogInfoOld)) {
            throw new BizException("此数据不存在");
        }
        if (ObjectUtils.isEmpty(display)) {
            throw new BizException("状态错误");
        }

        return this.update(new LambdaUpdateWrapper<UmsBlogInfo>()
                .set(UmsBlogInfo::getDisplay, display)
                .set(UmsBlogInfo::getDelReason, downReason)
                .eq(UmsBlogInfo::getId, id));
    }

    @Override
    public boolean delBlog(Long id, String reason) {
        //校验ID
        UmsBlogInfo umsBlogInfo = this.getById(id);
        if (ObjectUtils.isEmpty(umsBlogInfo)) {
            throw new BizException("没有找到该数据！");
        }

        return this.update(new LambdaUpdateWrapper<UmsBlogInfo>()
                .set(UmsBlogInfo::getDelReason, reason)
                .set(UmsBlogInfo::getDelUser, "admin")
                .set(UmsBlogInfo::getDeleted, true)
                .eq(UmsBlogInfo::getId, id));
    }

    @Override
    public boolean updateHotList(List<Long> idList, boolean hot) {

        if (CollectionUtils.isEmpty(idList)) {
            throw new BizException("没有选中数据");
        }
        boolean result = true;
        for (Long id : idList) {
            result = result && this.updateHot(id, hot);
        }

        return result;
    }

    @Override
    public boolean updateDisplayList(BlogDisplayForm form, boolean display) {
        List<Long> ids = form.getIds();
        if (CollectionUtils.isEmpty(ids)) {
            throw new BizException("没有选中数据");
        }

        String downReason = form.getDownReason();
        boolean result = true;
        for (Long id : ids) {
            result = result && this.updateDisplay(id, display, downReason);
        }

        return result;
    }


    /**
     * =========  基础功能 CRUD =========
     */
    @Override
    public boolean add(Long userId, String ipHost, String ipCity, UmsBlogInfoForm umsBlogInfoForm) {
        UmsUserDto userDto = userService.getUserDtoById(userId);
        if (ObjectUtils.isEmpty(userDto)) {
            throw new BizException("用户不存在");
        }

        // 变量定义
        boolean isClockIn = false;

        // 1，保存帖子/博客内容
        UmsBlogInfo umsBlogInfo = conversionToPojo(umsBlogInfoForm);
        umsBlogInfo.setUserId(userDto.getId());
        umsBlogInfo.setUserName(userDto.getNickname());
        umsBlogInfo.setUserAvatar(userDto.getAvatar());
        umsBlogInfo.setIpHost(ipHost);
        umsBlogInfo.setIpCity(ipCity);
        boolean save = this.save(umsBlogInfo);


        // todo 这里需求还未确定
        // 2，保存打卡关联关系
        String sourceType = umsBlogInfoForm.getSourceType();
        SignSourceTypeEnum anEnum = SignSourceTypeEnum.getEnum(sourceType);
        log.info("sourceType = {},anEnum = {}", sourceType, anEnum);
        if (StringUtils.isNotEmpty(sourceType)) {
            switch (Objects.requireNonNull(anEnum)) {
                case FLOWER:
                    isClockIn = true;
                    break;
                case LANDSCAPE:
                    isClockIn = true;
                    clockInService.add(UmsClockInForm.builder()
                            .userId(userId)
                            .placeInfoId(umsBlogInfoForm.getPlaceTypeId())
                            .sourceType(anEnum.name())
                            .build());
                    break;
                default:
                    log.info("打卡来源类型错误，sourceType = {}", sourceType);
            }
        }

        // 3， 保存标签关联关系
        List<Long> tableList = umsBlogInfoForm.getTableList();
        List<UmsBlogInfoTable> blogInfoTable = tableList.stream().map(s -> {
            return UmsBlogInfoTable.builder().blogInfoId(umsBlogInfo.getId()).tableId(s).build();
        }).collect(Collectors.toList());
        // 添加打卡的默认标签
        log.info("blogInfoTable = {},isClockIn = {}", blogInfoTable, isClockIn);
        if (isClockIn) {
            List<UmsBlogInfoTable> tempList = new ArrayList<>();
            UmsBlogTable clockInTable = tableService.getClockInTable(anEnum);
            tempList.add(UmsBlogInfoTable.builder().blogInfoId(umsBlogInfo.getId()).tableId(clockInTable.getId()).build());
            tempList.addAll(1, blogInfoTable);
            blogInfoTable = tempList;
            log.info(" blogInfoTable => {}", blogInfoTable);
        }

        if (CollectionUtils.isEmpty(blogInfoTable)) {
            log.info("没有关联的标签");
            return save;
        }

        boolean contactSave = blogInfoTableService.saveBatch(blogInfoTable);

        return save & contactSave;
    }

    @Override
    public Page<UmsBlogInfoVo> pageList(Integer page, Integer limit, Long userId, Integer display, Integer reviewStatus, boolean isSort, boolean isAll) {

        LambdaQueryWrapper<UmsBlogInfo> queryWrapper = new LambdaQueryWrapper<UmsBlogInfo>()
                .orderByDesc(UmsBlogInfo::getGmtCreate)
                .orderByDesc(UmsBlogInfo::getGmtModified);

        // 查询条件
        if (!isAll && ObjectUtils.isNotEmpty(userId)) {
            queryWrapper.eq(UmsBlogInfo::getUserId, userId);
        }
        if (ObjectUtils.isNotEmpty(display)) {
            queryWrapper.eq(UmsBlogInfo::getDisplay, display);
        }
        if (ObjectUtils.isNotEmpty(reviewStatus)) {
            queryWrapper.eq(UmsBlogInfo::getReviewStatus, reviewStatus);
        }
        if (isSort) {
            queryWrapper.orderByDesc(UmsBlogInfo::getSort);
        }

        Page<UmsBlogInfo> umsBlogInfoPage = this.page(new Page<>(page, limit), queryWrapper);
        if (umsBlogInfoPage.getTotal() == 0) {
            return new Page<>(page, limit);
        }

        List<UmsBlogInfoVo> umsBlogInfoList = umsBlogInfoPage.getRecords().stream().map(this::conversionToVo).collect(Collectors.toList());

        //处理是否点赞 是否是自己的博客
        if (ObjectUtils.isNotEmpty(userId)) {
            for (UmsBlogInfoVo vo : umsBlogInfoList) {
                vo.setLike(isLike(vo.getId(), userId));
                //判断是否是自己的博客
                vo.setMyBlog(isMyBlog(userId, vo.getUserId()));
            }
        }

        Page<UmsBlogInfoVo> umsBlogInfoVoPage = new Page<>(page, limit, umsBlogInfoPage.getTotal());
        umsBlogInfoVoPage.setRecords(umsBlogInfoList);

        return umsBlogInfoVoPage;
    }

    @Override
    public boolean update(UmsBlogInfoForm articleForm) {

        //校验ID
        UmsBlogInfo umsBlogInfoOld = this.getById(articleForm.getId());
        if (ObjectUtils.isEmpty(umsBlogInfoOld)) {
            throw new BizException("没有找到该数据！");
        }

        UmsBlogInfo umsBlogInfo = new UmsBlogInfo();
        BeanUtil.copyProperties(articleForm, umsBlogInfo);
        umsBlogInfo.setId(umsBlogInfoOld.getId());
        umsBlogInfo.setGmtModified(new Date());

        return this.updateById(umsBlogInfo);
    }

    @Override
    public boolean deleteByIds(List<String> asList) {
        if (CollectionUtils.isFull(asList)) {
            throw new BizException("没有选择任何数据，请重新操作！");
        }

        return this.removeByIds(asList);
    }

    @Override
    public UmsBlogInfoVo detail(Long id) {
        Long userId = RequestUtils.getUserId();

        UmsBlogInfo UmsBlogInfo = this.getById(id);

        UmsBlogInfoVo umsBlogInfoVo = conversionToVo(UmsBlogInfo);

        if (ObjectUtils.isNotEmpty(userId)) {
            umsBlogInfoVo.setLike(isLike(id, userId));
            umsBlogInfoVo.setMyBlog(isMyBlog(userId, id));
        }
        //判断是否是自己的博客
        umsBlogInfoVo.setMyBlog(isMyBlog(RequestUtils.getUserId(), umsBlogInfoVo.getUserId()));

        return umsBlogInfoVo;
    }

    /**
     * ===========  私有方法 ===========
     */


    private boolean isMyBlog(Long userId, Long blogUserId) {
        log.info("userId = {} ,blogUserId = {}", userId, blogUserId);
        if (ObjectUtils.isEmpty(userId)) {
            return false;
        }

        if (ObjectUtils.isNotEmpty(blogUserId) && blogUserId.equals(userId)) {
            return true;
        }
        return false;
    }

    private UmsBlogInfoVo conversionToVo(UmsBlogInfo umsBlogInfo) {
        if (ObjectUtils.isEmpty(umsBlogInfo)) {
            return new UmsBlogInfoVo();
        }

        UmsBlogInfoVo umsBlogInfoVo = new UmsBlogInfoVo();
        BeanUtil.copyProperties(umsBlogInfo, umsBlogInfoVo);

        //转换标签
        List<UmsBlogTableVo> tableVoList = tableService.findTableNameByBlogId(umsBlogInfo.getId());
        umsBlogInfoVo.setTableVoList(tableVoList);
        //转换审核状态
        String enumName = ReviewStatusEnum.getValue(umsBlogInfo.getReviewStatus()).getName();
        umsBlogInfoVo.setReviewStatusName(enumName);
        //转换图片列表
        umsBlogInfoVo.setImageUrlList(ImagerListUtil.conversionToList(umsBlogInfo.getImageUrl()));

        return umsBlogInfoVo;
    }

    private UmsBlogInfo conversionToPojo(UmsBlogInfoForm appsIconForm) {
        if (ObjectUtils.isEmpty(appsIconForm)) {
            throw new BizException("提交的数据表单为空");
        }

        UmsBlogInfo umsBlogInfo = new UmsBlogInfo();
        BeanUtil.copyProperties(appsIconForm, umsBlogInfo);

        return umsBlogInfo;
    }

    private UmsBlogComment conversionToCommentPojo(UmsBlogCommentForm form) {
        UmsBlogComment blogComment = new UmsBlogComment();
        BeanUtil.copyProperties(form, blogComment);

        return blogComment;
    }

    private UmsBlogCommentVo conversionToCommentVo(UmsBlogComment umsBlogComment) {
        UmsBlogCommentVo vo = new UmsBlogCommentVo();
        BeanUtil.copyProperties(umsBlogComment, vo);
        return vo;
    }

    private UmsBlogTableVo conversionToTableVo(UmsBlogTable pojo) {
        UmsBlogTableVo vo = new UmsBlogTableVo();
        BeanUtil.copyProperties(pojo, vo);
        return vo;
    }
}
